// --------------------------------------------------------------------------------------------------------------------
// <copyright file="VisionToolWrapperUnitTest.cs" company="Microsoft Corporation">
// The MIT License (MIT)
// 
// Copyright (c) 2014, Microsoft Corporation
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
// </copyright>
// --------------------------------------------------------------------------------------------------------------------

namespace Test.Robotics.Vision
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Threading;
    using Microsoft.Robotics.Numerics;
    using Microsoft.Robotics.Runtime;
    using Microsoft.Robotics.Vision;
    using Microsoft.Robotics.Vision.Runtime.Cameras;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Test.Robotics.Runtime;

    /// <summary>
    /// Test for Vision tool interop
    /// </summary>
    [TestClass]
    public class VisionToolWrapperUnitTest
    {
        /// <summary>
        /// Validation of low level feature extraction from image
        /// </summary>
        [Priority(1)]
        [TestMethod]
        [TestCategory("Unit")]
        public void VisionToolsExtractLowLevelFeaturesFromImage()
        {
            string filePath = @"\\robofile\Baker\Shared\Users\roboim\UnitTestData\Vision\VisionToolsTest.png";
            double expectCenterX = 338.5;
            double expectCenterY = 240.8;
            double expectMajorAxis = 153.8;

            ImageFrameRgb testFrame = ImageOperations2DInterop.LoadImageRgbFromFile(filePath);

            List<ImageEllipse> ellipses = ImageOperations2DInterop.GetEllipses(testFrame);

            // Check we found at least one expected ellipse
            bool foundExpected = false;

            Assert.IsTrue(ellipses.Count > 0, "Did not find any ellipses");
            foreach (ImageEllipse e in ellipses)
            {
                if (Math.Abs(e.CenterX - expectCenterX) < 0.1 &&
                    Math.Abs(e.CenterY - expectCenterY) < 0.1 &&
                    Math.Abs(e.MajorAxisLength - expectMajorAxis) < 0.1)
                {
                    foundExpected = true;
                }

                Assert.AreEqual(e.Size1D, Math.Sqrt(e.MajorAxisLength * e.MinorAxisLength) / 2, 0.001);
            }

            Assert.IsTrue(foundExpected);

            List<Shape2DCluster> clusters = (List<Shape2DCluster>)Shape2DCluster.Cluster(ellipses);
            Assert.IsTrue(clusters.Count > 0);

            foundExpected = false;
            foreach (Shape2DCluster c in clusters)
            {
                if (Math.Abs(c.CenterX - expectCenterX) < 1 &&
                    Math.Abs(c.CenterY - expectCenterY) < 1)
                {
                    foundExpected = true;
                }
            }

            Assert.IsTrue(foundExpected);
        }

        /// <summary>
        /// Validation of low level feature extraction
        /// </summary>
        [Priority(1)]
        [TestMethod]
        [Ignore]
        [TestCategory("Unit")]
        public void VisionToolsExtractLowLevelFeatures()
        {
            string filePath = @"\\robofile\Baker\Shared\Users\roboim\UnitTestData\Vision\VisionToolsTest.xml";
            int count = 2;
            double expectCenterX = 379.35;
            double expectCenterY = 255.58;
            double expectMajorAxis = 138.47;

            // Set up a simple pipeline to read the data file
            AgentLocator agentLocator = new AgentLocator(true);
            TimerAgent timer = new TimerAgent("FileTimer", 1);
            agentLocator.Register(timer);

            FilePlayerProxy player = new FilePlayerProxy(
                name: "player",
                filePath: filePath,
                messageTypes: new[] { typeof(RGBCameraAgentMessage) },
                timerAgent: timer,
                binarySerialization: false);
            agentLocator.Register(player);

            MessageCollectorAgent<RGBCameraAgentMessage> collectorAgent = new MessageCollectorAgent<RGBCameraAgentMessage>("collector", player.AsProducer<RGBCameraAgentMessage>(), count);
            IAgentHost collector = agentLocator.Register(collectorAgent);

            try
            {
                collector.Activate();

                player.Wait(500);
                DateTime start = DateTime.Now;

                while (collectorAgent.Results.Count <= 0 && (DateTime.Now - start).TotalMilliseconds < 500)
                {
                    Thread.Sleep(10);
                }

                Assert.IsTrue(collectorAgent.Results.Count > 0, "No messages appear at the end of the pipeline");

                // Check we found at least one expected ellipse
                bool foundExpected = false;

                while (collectorAgent.Results.Count > 0)
                {
                    RGBCameraAgentMessage r = collectorAgent.Results.Dequeue();
                    ImageFrameRgb rgbImage = ImageOperations2DInterop.ConvertYUY2ToRGBImage(r.RGBImageFrame);
                    {
                        Assert.IsTrue(ImageOperations2DInterop.GetEllipses(rgbImage).Count > 0, "Did not find any ellipses");
                        foreach (ImageEllipse e in ImageOperations2DInterop.GetEllipses(rgbImage))
                        {
                            if (Math.Abs(e.CenterX - expectCenterX) < 0.1 &&
                                Math.Abs(e.CenterY - expectCenterY) < 0.1 &&
                                Math.Abs(e.MajorAxisLength - expectMajorAxis) < 0.1)
                            {
                                foundExpected = true;
                            }
                        }
                    }
                }

                Assert.IsTrue(foundExpected);
            }
            catch (Exception)
            {
                throw;
            }
            finally
            {
                collector.Deactivate();
            }
        }
    }
}
